#!/usr/bin/env python
# -*- coding:utf-8 -*-
  
import tornado.ioloop
import tornado.web
from hashlib import sha1
import os, time
  
session_container = {}  #session_container是session_id下面所有的东西
  
create_session_id = lambda: sha1('%s%s' % (os.urandom(16), time.time())).hexdigest()
  
  
class Session(object):
  
    session_id = "session_cookie"   #名字可以随便起，标识cookie

    '''初始化，session_id是服务器生成，浏览器第一次访问时服务器给它写入的，是一个存储session等信息的字典
    当用户请求来了，创建LoginHandler对象，然后初始化BaseHandler类中的initialize方法，它调用了Session类的构造函数，
    服务器会去request中获取cookie（request.get_cookie(session_cookie)）:
        如果request中session_cookie有值，那么self._id就是获取到的session字典最外层key
        如果没有值，就创建一个cookie字典，self._id=一个随机字符串，作为session字典最外层key，这个key下面还有一层字典
    最后，再给浏览器的session_cookie设置一遍cookie，外层key就是_id，内层是自定义内容。
    '''
    def __init__(self, request):
        session_value = request.get_cookie(Session.session_id)
        if not session_value:
            self._id = create_session_id()
        else:
            self._id = session_value
        request.set_cookie(Session.session_id, self._id)

    #不进行异常处理会报key error错
    #因为用户第一次来请求就会先触发get请求查询cookie值，调取此方法，但是里面为空，所以会报错
    def __getitem__(self, key):
        ret = None
        try:
            ret = session_container[self._id][key]
        except Exception,e:
            print e
        return ret

    '''当调用对象的set方法时，会自动触发此函数执行
    过程是将get中要在session中设置的值以字典的形式添加到session_container中
    记住_id是那个随机字符串，它是第二层key
    此时session_container这个全局变量中就存储了session等信息，每当用户来get请求的时候，就可以判断session的内容'''
    def __setitem__(self, key, value):
        if session_container.has_key(self._id):
            session_container[self._id][key] = value
        else:
            session_container[self._id] = {key: value}
  
    def __delitem__(self, key):
        del session_container[self._id][key]
  
  
class BaseHandler(tornado.web.RequestHandler):

    '''执行initialize方法，就是服务器生成cookie字典并向浏览器写入，参数self就是子类LoginHandler的对象
    创建对象时，initialize是在LoginHandler的get方法之前执行的，所以self.my_session字段在get方法中也能获取到
    self.my_session字段是初始化Session类，参数self是LoginHandler类对象，去Session类中init都干了什么；
    为浏览器创建完cookie，再去执行get方法中的内容，此时self.my_session就是这个cookie字典。
    self.my_session = {'session_cookie':{'_id':{'is_login':true,'name'='xxx'},},}
    '''
    def initialize(self):
        # my_session['k1']访问 __getitem__ 方法
        self.my_session = Session(self)
  
  
class MainHandler(BaseHandler):
  
    def get(self):
        print self.my_session['c_user']
        print self.my_session['c_card']
        self.write('index')
  
class LoginHandler(BaseHandler):

    '''当用户get方式请求/login路径时，执行此函数
    此时服务器端会生成一个随机字符串为key的字典，写入客户端浏览器，这个叫session_cookie，作为客户端以后请求的标识
    LoginHandler继承了BaseHandler，而BaseHandler是我自己定义的类，BaseHandler又继承了RequestHandler类
    BaseHandler中就可以自定义扩展方法，从而在执行get函数之前，就会先执行BaseHandler类中的initialize方法
    此时如果创建一个obj=LoginHandler(),那么obj.initialize(),就是执行BaseHandler中的initialize函数
    '''
    def get(self):
        '''此时session_container这个全局变量中已经存储了session等信息，每当用户来get请求的时候，就可以判断session的内容
        根据内容是否跳转到目的页面，还是重新登录'''
        if session_container[self._id]['is_login'] == 'True':
            self.redirect('/index')
        else:
            self.render('login.html', **{'status': ''})

    '''当用户提交一个form表单时，也就是post请求，执行此函数
    获取到用户输入的name和pwd属性的值，如果匹配，就跳转到index页面，反之，就会报告错误信息
    当验证通过的时候，可以向自定义的session_cookie中写入一些key&value，比如：is_login=true,但是它是字典形式保存'''
    def post(self, *args, **kwargs):
  
        username = self.get_argument('name')
        password = self.get_argument('pwd')
        if username == 'wupeiqi' and password == '123':
            '''当执行对象（）的set方法时，自动触发执行__setitem__方法，self.my_session是Session类的对象，
            所以设置下面值的时候会触发Sesstion类中的__setitem__方法'''
            # self.my_session.set('c_user','wupeiqi') = 'wupeiqi'
            self.my_session['c_user'] = 'wupeiqi'
            self.my_session['c_card'] = '12312312309823012'
  
            self.redirect('/index')
        else:
            self.render('login.html', **{'status': '用户名或密码错误'})
  
settings = {
    'template_path': 'template',
    'static_path': 'static',
    'static_url_prefix': '/static/',
    'cookie_secret': 'aiuasdhflashjdfoiuashdfiuh',
    'login_url': '/login'
}

'''创建application对象，其中有两条映射，分别对应MainHandler类和LoginHandler类来处理请求
当用户打开某一个url（get请求），就（通过函数反射）执行对应类的get函数'''
application = tornado.web.Application([
    (r"/index", MainHandler),
    (r"/login", LoginHandler),
], **settings)
  
  
if __name__ == "__main__":
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()